/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>

#include "log.h"
#include "bts_le_gap.h"
#include "ohos_bt_gatt.h"

static BtGattCallbacks *g_bleGapCb = NULL;
extern void gatt_state_change_callback(int connId, const BdAddr *bdAddr, int state);

int BleSetAdvData(int advId, const StartAdvRawData data)
{
    gap_ble_config_adv_data_t advData = {0};

    HILOG_DEBUG(0, "[bluetooth] BleSetAdvData\n");

    advData.adv_data = data.advData;
    advData.adv_length = data.advDataLen;
    advData.scan_rsp_data = data.rspData;
    advData.scan_rsp_length = data.rspDataLen;
    return gap_ble_set_adv_data(advId, &advData);
}

int BleStartAdv(int advId, const BleAdvParams *param)
{
    errcode_t ret = ERRCODE_BT_FAIL;
    gap_ble_adv_params_t advParams = {0};

    HILOG_DEBUG(0, "[bluetooth] BleStartAdv\n");

    advParams.min_interval         = param->minInterval;
    advParams.max_interval         = param->maxInterval;
    advParams.duration             = param->duration;
    advParams.channel_map          = param->channelMap;
    advParams.adv_type             = param->advType;
    advParams.adv_filter_policy    = param->advFilterPolicy;
    advParams.peer_addr.type       = param->peerAddrType;
    advParams.own_addr.type        = param->ownAddrType;
    advParams.tx_power             = param->txPower;
    (void)memcpy_s(&advParams.peer_addr.addr, BD_ADDR_LEN, param->peerAddr.addr, BD_ADDR_LEN);
    (void)memset_s(&advParams.own_addr.addr, BD_ADDR_LEN, 0, BD_ADDR_LEN);
    ret = gap_ble_set_adv_param(advId, &advParams);
    if (ret != ERRCODE_BT_SUCCESS) {
        HILOG_ERROR(0, "[bluetooth] BleStartAdv Error:%d\n", ret);
        return ret;
    }

    return gap_ble_start_adv(advId);
}

int BleStopAdv(int advId)
{
    HILOG_DEBUG(0, "[bluetooth] BleStopAdv\n");

    return gap_ble_stop_adv(advId);
}

static void ble_enable_callback(errcode_t status)
{
    HILOG_DEBUG(0, "[bluetooth] ble_enable_callback status:%d.\n", status);
}

static void ble_disable_callback(errcode_t status)
{
    HILOG_DEBUG(0, "[bluetooth] ble_disable_callback status:%d.\n", status);
}

static void set_adv_data_callback(uint8_t adv_id, errcode_t status)
{
    HILOG_DEBUG(0, "[bluetooth] set_adv_data_callback status:%d.\n", status);

    g_bleGapCb->advDataCb(adv_id, status);
}

static void set_adv_param_callback(uint8_t adv_id, errcode_t status)
{
    HILOG_DEBUG(0, "[bluetooth] set_adv_param_callback status:%d.\n", status);
}

static void start_adv_callback(uint8_t adv_id, adv_status_t status)
{
    HILOG_DEBUG(0, "[bluetooth] start_adv_callback status:%d.\n", status);

    if (status == ADV_STATUS_ADVERTISING) {
        g_bleGapCb->advEnableCb(adv_id, 0);
    } else {
        g_bleGapCb->advEnableCb(adv_id, OHOS_BT_STATUS_FAIL);
    }
}

static void stop_adv_callback(uint8_t adv_id, adv_status_t status)
{
    HILOG_DEBUG(0, "[bluetooth] stop_adv_callback status:%d.\n", status);

    if (status == ADV_STATUS_STOPPED) {
        g_bleGapCb->advDisableCb(adv_id, 0);
    } else {
        g_bleGapCb->advDisableCb(adv_id, OHOS_BT_STATUS_FAIL);
    }
}

static void conn_state_change_callback(uint16_t conn_id, bd_addr_t *addr,
    gap_ble_conn_state_t conn_state, gap_ble_pair_state_t pair_state, gap_ble_disc_reason_t disc_reason)
{
    HILOG_DEBUG(0, "[bluetooth] conn_state_change_callback "
        "conn_id: %d, status: %d, pair_status:%d, disc_reason:%x\n",
        conn_id, conn_state, pair_state, disc_reason);

    BdAddr bd_addr = {0};
    (void)memcpy_s(bd_addr.addr, BD_ADDR_LEN, addr->addr, BD_ADDR_LEN);
    gatt_state_change_callback(conn_id, &bd_addr, conn_state);
}

static gap_ble_callbacks_t g_gapCallback = {
    .ble_enable_cb          = ble_enable_callback,
    .ble_disable_cb         = ble_disable_callback,
    .set_adv_data_cb        = set_adv_data_callback,
    .set_adv_param_cb       = set_adv_param_callback,
    .set_scan_param_cb      = NULL,
    .start_adv_cb           = start_adv_callback,
    .stop_adv_cb            = stop_adv_callback,
    .scan_result_cb         = NULL,
    .conn_state_change_cb   = conn_state_change_callback,
};

int BleGattRegisterCallbacks(BtGattCallbacks *func)
{
    if (func == NULL) {
        HILOG_ERROR(0, "[bluetooth] BleGattRegisterCallbacks func is NULL\n");
        return -1;
    }

    HILOG_DEBUG(0, "[bluetooth] BleGattRegisterCallbacks\n");

    g_bleGapCb = func;
    return gap_ble_register_callbacks(&g_gapCallback);
}
